from datetime import datetime
import time
from .telegram_bot import bot
from telebot.types import (InlineKeyboardButton, 
                          InlineKeyboardMarkup, 
                          ReplyKeyboardMarkup)
from config import (chunk_default,
                    chat_default,
                    basic_add_timings,
                    basic_id_types_non_rem,
                    basic_id_subtypes_non_rem,
                    Callbacks,
                    ButtonsInput, 
                    GroupingTasksMenu)


def send_message_problem(message:str, value_infinite:bool=False) -> None:
    """
    Function that is dedicated to send values in cases of the errors
    Input:  message = text of the message which is sending values
            value_infinite = bool value which is for the infinite checking
    Output: message for the admin which to develop values
    """
    if value_infinite:
        for chat in chat_default:
            bot.send_message(chat, message)
    else:
        message = f"{message}\nIt's infinite message"
        while True:
            for chat in chat_default:
                bot.send_message(chat, message)
            time.sleep(600)

def develop_basic_input() -> object:
    """
    Function which is dedicated for developing values of it
    Input:  None values
    Output: we developed values of it
    """
    markup_test = ReplyKeyboardMarkup(
        resize_keyboard=True, 
        one_time_keyboard=True, 
        row_width=1)
    markup_test.row(
        ButtonsInput.button_types, 
        ButtonsInput.button_subtypes)
    markup_test.row(
        ButtonsInput.button_characteristics, 
        ButtonsInput.button_tasks, 
        ButtonsInput.button_help)
    markup_test.row(
        ButtonsInput.button_settings, 
        ButtonsInput.button_support)
    return markup_test

def develop_grouping_showings(def_types:int, def_subtypes:int, def_tasks:int) -> int:
    """
    Function which is developed values of the grouping showings 
    Input:  def_types = default by types by
            def_subtypes = default by subtypes values
            def_tasks = default by tasks values
    Output: int value how to show values for it
    """
    if def_types:
        return 1
    if def_subtypes:
        return 2
    if def_tasks:
        return 3
    return 4

def develop_user_settings_frequency(frequency_list:list, frequency_id:int, user_id:int) -> object:
    """
    Function which is dedicated to create object of change of default frequency
    Input:  frequency_list = list of the user frequencies
            frequency_id = id of the selected frequency
            user_id = id of the selected user
    Output: we developed values of the keyboard to change settings frequency
    """
    value_buttons = [
        InlineKeyboardButton(
            f"{name}|{ButtonsInput.button_empty}" if frequency_id != id_freq\
                else f"{name}|{ButtonsInput.button_present}",
            callback_data=\
                f"{Callbacks.callback_settings_new_frequency}_{id_freq}_{frequency_id}_{user_id}" \
                if frequency_id != id_freq else Callbacks.callback_empty) 
        for id_freq, name in frequency_list]
    return InlineKeyboardMarkup(
        produce_list_chunks(
            value_buttons, 
            2))

def develop_input_user_statistics(statistics_list:list) -> object:
    """
    Function which is dedicated to develop the statistics values
    Input:  statistics_list = list which was previously used
            user_id = id of the users which required that
    Output: we created Markup for the user
    """
    (number_proc, datetime_started), number_exp, number_fin  = statistics_list
    number_sum = number_proc + number_exp + number_fin
    return InlineKeyboardMarkup([
        [
            InlineKeyboardButton(
                f"{ButtonsInput.button_show_processing}|{ButtonsInput.button_present}" if number_proc \
                    else f"{ButtonsInput.button_show_processing}|{ButtonsInput.button_empty}",
                callback_data=Callbacks.callback_empty),
            InlineKeyboardButton(
                number_proc,
                callback_data=f"{Callbacks.callback_task_selection}_1" if number_proc \
                    else Callbacks.callback_empty),
            InlineKeyboardButton(
                f"{round(number_proc / number_sum, 2) * 100} %" if number_sum else "0 %",
                callback_data=Callbacks.callback_empty)
            ],
        [
            InlineKeyboardButton(
                f"{ButtonsInput.button_show_expired}|{ButtonsInput.button_present}" if number_exp \
                    else f"{ButtonsInput.button_show_expired}|{ButtonsInput.button_empty}",
                callback_data=Callbacks.callback_empty),
            InlineKeyboardButton(
                number_exp,
                callback_data=f"{Callbacks.callback_task_selection}_2" if number_exp \
                    else Callbacks.callback_empty),
            InlineKeyboardButton(
                f"{round(number_exp / number_sum, 2) * 100} %"  if number_exp else "0 %",
                callback_data=Callbacks.callback_empty)
            ],
        [
            InlineKeyboardButton(
                f"{ButtonsInput.button_show_finished}|{ButtonsInput.button_present}" if number_fin \
                    else f"{ButtonsInput.button_show_finished}|{ButtonsInput.button_empty}",
                callback_data=Callbacks.callback_empty),
            InlineKeyboardButton(
                number_fin,
                callback_data=f"{Callbacks.callback_task_selection}_3" if number_fin \
                    else Callbacks.callback_empty),
            InlineKeyboardButton(
                f"{round(number_fin / number_sum, 2) * 100} %"  if number_fin else "0 %",
                callback_data=Callbacks.callback_empty)
            ],
        [
            InlineKeyboardButton(
                ButtonsInput.button_show_datetime,
                callback_data=Callbacks.callback_empty),
            InlineKeyboardButton(
                datetime_started if datetime_started else 'Unknown',
                callback_data=Callbacks.callback_empty)
            ]
    ])

def develop_input_user_settings(settings_list:list, user_id:int, index:int=1) -> object:
    """
    Function which is dedicated for returning user settings
    Input:  user_id = id of the user 
    Output: object which is dedicated to return values of the settings menu
    """
    def_types, def_subtypes, def_tasks, \
    s_processing, s_expired, s_finished, \
    add_timing, frequency_id, frequency, \
        morning, day, evening = settings_list
    settings_markup_list = [
        [
            [
                InlineKeyboardButton(
                    ButtonsInput.button_default_task_group,
                    callback_data=Callbacks.callback_empty
                )
            ],
            [
                InlineKeyboardButton(
                    f"{GroupingTasksMenu.default_types}|{ButtonsInput.button_present}" if def_types \
                            else f"{GroupingTasksMenu.default_types}|{ButtonsInput.button_empty}",
                    callback_data=f"{Callbacks.callback_settings_group_types}_{user_id}" \
                        if not def_types else Callbacks.callback_empty
                ),
                InlineKeyboardButton(
                    f"{GroupingTasksMenu.default_subtypes}|{ButtonsInput.button_present}" if def_subtypes \
                        else f"{GroupingTasksMenu.default_subtypes}|{ButtonsInput.button_empty}",
                    callback_data=f"{Callbacks.callback_settings_group_subtypes}_{user_id}" \
                        if not def_subtypes else Callbacks.callback_empty
                )
            ],
            [
                InlineKeyboardButton(
                f"{GroupingTasksMenu.default_task}|{ButtonsInput.button_present}" if def_tasks \
                    else f"{GroupingTasksMenu.default_task}|{ButtonsInput.button_empty}",
                callback_data=f"{Callbacks.callback_settings_group_task}_{user_id}" \
                        if not def_tasks else Callbacks.callback_empty
            ),
                InlineKeyboardButton(
                    GroupingTasksMenu.default_back,
                    callback_data=f"{Callbacks.callback_settings_group_default}_{user_id}" \
                        if any([def_types, def_subtypes, def_tasks]) else Callbacks.callback_empty
                )
            ],
            [
                InlineKeyboardButton(
                    ButtonsInput.button_default_task_frequency,
                    callback_data=Callbacks.callback_empty
                )
            ],
            [
                InlineKeyboardButton(
                    frequency,
                    callback_data=\
                        f"{Callbacks.callback_settings_change_frequency}_{frequency_id}_{user_id}"
                )
            ],
            [
               InlineKeyboardButton(
                    ButtonsInput.button_default_task_show,
                    callback_data=Callbacks.callback_empty
                ) 
            ],
            [
                InlineKeyboardButton(
                    f"{ButtonsInput.button_show_processing}|{ButtonsInput.button_present}" if s_processing \
                        else f"{ButtonsInput.button_show_processing}|{ButtonsInput.button_empty}",
                    callback_data=\
                        f"{Callbacks.callback_settings_change_showings}_{s_processing}_{1}_{user_id}"
                ),
                InlineKeyboardButton(
                    f"{ButtonsInput.button_show_expired}|{ButtonsInput.button_present}" if s_expired \
                        else f"{ButtonsInput.button_show_expired}|{ButtonsInput.button_empty}",
                    callback_data=\
                        f"{Callbacks.callback_settings_change_showings}_{s_expired}_{2}_{user_id}"
                ),
                InlineKeyboardButton(
                    f"{ButtonsInput.button_show_finished}|{ButtonsInput.button_present}" if s_finished \
                        else f"{ButtonsInput.button_show_finished}|{ButtonsInput.button_empty}",
                    callback_data=\
                        f"{Callbacks.callback_settings_change_showings}_{s_finished}_{3}_{user_id}"
                )
            ],
            [
                InlineKeyboardButton(
                    ButtonsInput.button_previous,
                    callback_data=f"{Callbacks.callback_settings_next}_{user_id}_1"
                ),
                InlineKeyboardButton(
                    "1 / 2",
                    callback_data=Callbacks.callback_empty
                ),
                InlineKeyboardButton(
                    ButtonsInput.button_next,
                    callback_data=f"{Callbacks.callback_settings_next}_{user_id}_1"
                )
            ]
        ],
        [
            [
                InlineKeyboardButton(
                    ButtonsInput.button_default_task_day,
                    callback_data=Callbacks.callback_empty
                )
            ],
            [
                InlineKeyboardButton(
                    f"{ButtonsInput.button_morning}|{ButtonsInput.button_present}" if morning \
                        else f"{ButtonsInput.button_morning}|{ButtonsInput.button_empty}",
                    callback_data=\
                        f"{Callbacks.callback_settings_change_datetime_not}_{morning}_1_{user_id}"
                ),
                InlineKeyboardButton(
                    f"{ButtonsInput.button_day}|{ButtonsInput.button_present}" if day \
                        else f"{ButtonsInput.button_day}|{ButtonsInput.button_empty}",
                    callback_data=\
                        f"{Callbacks.callback_settings_change_datetime_not}_{day}_2_{user_id}"
                ),
                InlineKeyboardButton(
                    f"{ButtonsInput.button_evening}|{ButtonsInput.button_present}" if evening \
                        else f"{ButtonsInput.button_evening}|{ButtonsInput.button_empty}",
                    callback_data=\
                        f"{Callbacks.callback_settings_change_datetime_not}_{evening}_3_{user_id}"
                )
            ],
            [
                InlineKeyboardButton(
                    ButtonsInput.button_default_add_timing,
                    callback_data=Callbacks.callback_empty
                )
            ],
            [
                InlineKeyboardButton(
                    f"{number}|{ButtonsInput.button_present}" if number==add_timing \
                        else f"{number}|{ButtonsInput.button_empty}",
                    callback_data=\
                        f"{Callbacks.callback_settings_change_add_timing}_{number}_{user_id}"
                )
                for number in basic_add_timings[:4]
            ],
            [
                InlineKeyboardButton(
                    f"{number}|{ButtonsInput.button_present}" if number==add_timing \
                        else f"{number}|{ButtonsInput.button_empty}",
                    callback_data=\
                        f"{Callbacks.callback_settings_change_add_timing}_{number}_{user_id}"
                )
                for number in basic_add_timings[4:]
            ],
            [
                InlineKeyboardButton(
                    ButtonsInput.button_previous,
                    callback_data=f"{Callbacks.callback_settings_next}_{user_id}_0"
                ),
                InlineKeyboardButton(
                    "2 / 2",
                    callback_data=Callbacks.callback_empty
                ),
                InlineKeyboardButton(
                    ButtonsInput.button_next,
                    callback_data=f"{Callbacks.callback_settings_next}_{user_id}_0"
                )
            ]
        ]
    ]
    return InlineKeyboardMarkup(settings_markup_list[index])

def return_message_greetings(value_menu:bool=False) -> str:
    """
    Function which is dedicated to return greetings messages
    Input:  value_menu = boolean value which is dedicated 
    Output: text message for the newcomers
    """
    if value_menu:
        return GroupingTasksMenu.text_menu
    return GroupingTasksMenu.text_start

def redevelop_values_results_task_query(value_list:list, value_type:int) -> list:
    """
    Function which is dedicated to develop values of the
    Input:  value_list = list values of the developed values
            value_type = value type of the which task which is developed
    Output: list of the values with the transform
    """
    value_list = [list(f) for f in value_list]
    if not value_list:
        return value_list
    if value_type == 1:
        value_insert = ButtonsInput.button_processing
    elif value_type == 2:
        value_insert = ButtonsInput.button_expired
    elif value_type == 3:
        value_insert = ButtonsInput.button_finished
    for value_in in value_list:
        if value_in:
            value_in.insert(1, value_insert)
    return value_list

def return_message_info_type(user_id:int, *args:set) -> set:
    """
    Function which is dedicated to get info message of the
    Input:  user_id = id of the user which created the info search
            args = set of the calculated values
    Output: string/object values which shows the information about type
    """
    type_main, type_default, type_processing, \
        type_expired, type_finished, type_subtype = args
    type_id, type_name = type_main
    type_default = "This type is `default`" \
        if type_default else 'This type `was created by you`'
    type_main = f"Full id: `{type_id}`\nFull name: `{type_name}`"
    type_processing = f'Number of proccessing tasks with this type: `{type_processing}`'
    type_expired = f'Number of expired tasks with this type: `{type_expired}`'
    type_finished = f'Number of finished tasks with this type: `{type_finished}`'

    return '\n'.join([type_main, type_default, type_processing, type_expired,
        type_finished]), develop_output_user_subtype(user_id, type_subtype, 0)

def return_message_info_subtype(user_id:int, *args:set) -> set:
    """
    Function which is dedicated to 
    Input:  user_id = id of the selected user
            args = set of the calculated values
    Output: string/object values which shows the information about subtype
    """
    subtype_main, subtype_default, subtype_processing, \
        subtype_expired, subtype_finished, subtype_type = args
    subtype_id, subtype_name = subtype_main
    subtype_default = "This subtype is `default`" \
        if subtype_default else 'This subtype `was created by you`'
    subtype_main = f"Full id: `{subtype_id}`\nFull name: `{subtype_name}`"
    subtype_processing = f'Number of proccessing tasks with this type: `{subtype_processing}`'
    subtype_expired = f'Number of expired tasks with this type: `{subtype_expired}`'
    subtype_finished = f'Number of finished tasks with this type: `{subtype_finished}`'

    return '\n'.join([subtype_main, subtype_default, subtype_processing, 
        subtype_expired, subtype_finished]), develop_output_user_type(user_id, subtype_type, 0)

def develop_output_tasks_unknown(user_id:int) -> object:
    """
    Function which is dedicated to return the keyboard for the selection of it
    Input:  user_id = id of the selected user to make this
    Output: we developed the keyboard for the selection all of it
    """
    markup_task = InlineKeyboardMarkup()
    markup_task.row_width = 3
    markup_task.add(
        InlineKeyboardButton(
            GroupingTasksMenu.group_types, 
            callback_data=Callbacks.callback_types_group),
        InlineKeyboardButton(
            GroupingTasksMenu.group_subtypes, 
            callback_data=Callbacks.callback_subtypes_group))
    markup_task.add(
        InlineKeyboardButton(
            GroupingTasksMenu.group_task, 
            callback_data=Callbacks.callback_task_group),
        InlineKeyboardButton(
            ButtonsInput.button_settings, 
            callback_data=Callbacks.callback_settings))
    markup_task.add(
        InlineKeyboardButton(
            GroupingTasksMenu.default_types, 
            callback_data=f"{Callbacks.callback_types_default}_{user_id}"))
    markup_task.add(
        InlineKeyboardButton(
            GroupingTasksMenu.default_subtypes, 
            callback_data=f"{Callbacks.callback_subtypes_default}_{user_id}"),
        InlineKeyboardButton(
            GroupingTasksMenu.default_task, 
            callback_data=f"{Callbacks.callback_task_default}_{user_id}"))
    return markup_task

def develop_output_user_subtype(user_id:int, user_subtypes:list, user_number:int=0) -> object:
    """
    Function which is dedicated to return all values of the subtypes of the user
    Input:  user_id = id of the user to develop
            user_subtypes = subtypes which where previously got of the user
            user_number = number of the index of the selection
    Output: menu for the subtypes of the selected user
    """
    if not user_subtypes:
        return None
    user_subtypes = produce_list_chunks(user_subtypes, 4)
    all_user_subtypes = len(user_subtypes)
    user_number = user_number % all_user_subtypes
    user_subtypes = user_subtypes[user_number]
    user_buttons = []
    for subtype_id, subtype_name in user_subtypes:
        if subtype_id not in basic_id_subtypes_non_rem:
            delete_text = ButtonsInput.button_empty
            delete_callback = \
                f"{Callbacks.callback_remove_user_subtype}_{subtype_id}_{user_number}_{user_id}"
        else:
            delete_text = ' '
            delete_callback = Callbacks.callback_empty
        user_buttons.append(
            [
                InlineKeyboardButton(
                subtype_name,
                callback_data=\
                    f"{Callbacks.callback_info_subtypes}_{user_id}_{subtype_id}"),
                InlineKeyboardButton(
                    ButtonsInput.button_show_tasks,
                    callback_data=\
                        f"{Callbacks.callback_show_tasks_by_subtypes}_{user_id}_{subtype_id}"
                ),
                InlineKeyboardButton(
                    ButtonsInput.button_move_subtype,
                    callback_data=f'{Callbacks.callback_move_task_by_subtypes}_{subtype_id}_{user_id}'
                ),
                InlineKeyboardButton(
                    delete_text,
                    callback_data=delete_callback
                )
            ]
        )
    if all_user_subtypes > 1:
        user_buttons.append(
            [
                InlineKeyboardButton(
                    ButtonsInput.button_previous,
                    callback_data=\
                        f"{Callbacks.callback_update_subtypes}_{user_id}_{user_number - 1}"),
                InlineKeyboardButton(
                    f"{user_number + 1}/{all_user_subtypes}",
                    callback_data=Callbacks.callback_empty),
                InlineKeyboardButton(
                    ButtonsInput.button_next,
                    callback_data=\
                        f"{Callbacks.callback_update_subtypes}_{user_id}_{user_number + 1}")
            ])
    markup_subtype = InlineKeyboardMarkup(user_buttons)
    markup_subtype.row_width = 3
    return markup_subtype

def develop_output_user_type(user_id:int, user_types:list, user_number:int=0) -> object:
    """
    Function which is dedicated to return all values of the user
    Input:  user_id = id of the user to develop
            user_types = types which were previously got here
            user_number = number of the index list
    Output: menu for the types of the selected user
    """
    if not user_types:
        return None
    user_types = produce_list_chunks(user_types, 3)
    all_user_types = len(user_types)
    user_number = user_number % all_user_types
    user_types = user_types[user_number]
    user_buttons = []
    for type_id, type_name in user_types:
        if type_id not in basic_id_types_non_rem:
            delete_text = ButtonsInput.button_empty
            delete_callback = \
                f"{Callbacks.callback_remove_user_type}_{type_id}_{user_number}_{user_id}"
        else:
            delete_text = ' '
            delete_callback = Callbacks.callback_empty
        user_buttons.append(
            [
            InlineKeyboardButton(
                type_name,
                callback_data=\
                    f"{Callbacks.callback_info_types}_{user_id}_{type_id}"),
            InlineKeyboardButton(
                ButtonsInput.button_show_tasks,
                callback_data=f"{Callbacks.callback_show_tasks_by_types}_{user_id}_{type_id}"
            ),
            InlineKeyboardButton(
                ButtonsInput.button_move_subtype,
                callback_data=f'{Callbacks.callback_move_task_by_types}_{type_id}_{user_id}'
            ),
            InlineKeyboardButton(
                delete_text,
                callback_data=delete_callback
            )])
    if all_user_types > 1:
        user_buttons.append(
            [
                InlineKeyboardButton(
                    ButtonsInput.button_previous,
                    callback_data=\
                        f"{Callbacks.callback_update_types}_{user_id}_{user_number - 1}"),
                InlineKeyboardButton(
                    f"{user_number + 1}/{all_user_types}",
                    callback_data=Callbacks.callback_empty),
                InlineKeyboardButton(
                    ButtonsInput.button_next,
                    callback_data=\
                        f"{Callbacks.callback_update_types}_{user_id}_{user_number + 1}")
            ])
    markup_type = InlineKeyboardMarkup(user_buttons)
    markup_type.row_width = 3
    return markup_type

def develop_output_tasks_update_frequency(not_list:list, user_id:int, task_id:int, not_id:int, index:int=0) -> object:
    """
    Function which is dedicated to return values of the updating frequency of the task
    Input:  not_list = list of the notifications to get
            user_id = id of the selected user to work with
            task_id = id of the selected task which to work with
            not_id = id of the notification which previously was used
    Output: Keyboard to change this values
    """
    value_list_input = [
        InlineKeyboardButton(
            f"{name}|{ButtonsInput.button_empty}" if id!=not_id else f"{name}|{ButtonsInput.button_present}",
            callback_data=f"{Callbacks.callback_update_tasks_frequency}_{task_id}_{not_id}_{id}_{index}_{user_id}"
        )
        for id, name in not_list]
    value_list_input = produce_list_chunks(value_list_input, 6)
    value_length = len(value_list_input)
    index = index % value_length
    value_list_input = [produce_list_chunks(v, 2) for v in value_list_input]
    if len(value_list_input) > 1:
        for v in value_list_input:
            v.append([
                InlineKeyboardButton(
                    ButtonsInput.button_previous,
                    callback_data=\
                        f"{Callbacks.callback_update_tasks_frequency_next}_{index - 1}_{task_id}_{not_id}_{user_id}"
                ),
                InlineKeyboardButton(
                    f"{index + 1}/{value_length}",
                    callback_data=Callbacks.callback_empty
                ),
                InlineKeyboardButton(
                    ButtonsInput.button_next,
                    callback_data=\
                        f"{Callbacks.callback_update_tasks_frequency_next}_{index + 1}_{task_id}_{not_id}_{user_id}"
                ),
            ])
    return InlineKeyboardMarkup(value_list_input[index]) if value_list_input[index] else None    

def develop_output_moving_tasks(type_list:list, id_old:int, id_user:int, type_use:bool=True, index:int=0) -> object:
    """
    Method which is dedicated to develop values of the miving own tasks to it 
    Input:  callback_move = list of the callback which we would_user
            type_list = list of the values which is used_currently
            id_old = id of the old type/subtype
            id_user = id of the user which is userd
            type_use = type of the type/subtype
            index = index of the selected new values
    Output: We developed moving tasks menu for the development output
    """
    if type_use:
        callback_select = Callbacks.callback_find_move_task_types
        callback_next = Callbacks.callback_next_move_task_types
        number_max = 9
        number_row = 3
    else:
        callback_select = Callbacks.callback_find_move_task_subtypes
        callback_next = Callbacks.callback_next_move_task_subtypes
        number_max = 8
        number_row = 2
    value_list_input = []
    type_list = produce_list_chunks(type_list, number_max)
    value_length = len(type_list)
    for type_lists in type_list:
        value_input = []
        for ind, (id_type, name_type) in enumerate(type_lists):
            if id_type != id_old:
                value_name_type = f'{name_type}|{ButtonsInput.button_empty}'
                value_name_callback = f"{callback_select}_{id_old}_{id_type}_{ind}_{id_user}"
            else:
                value_name_type = f'{name_type}|{ButtonsInput.button_present}'
                value_name_callback = Callbacks.callback_empty
            value_input.append(
                InlineKeyboardButton(
                    value_name_type,
                    callback_data=value_name_callback
            ))
        value_list_input.append(value_input)
    index = index % value_length
    value_list_input = [produce_list_chunks(f, number_row) for  f in value_list_input]
    if value_length > 1:
        for ind, value_list in enumerate(value_list_input):
            value_list.append([
                InlineKeyboardButton(
                    ButtonsInput.button_previous,
                    callback_data=\
                        f"{callback_next}_{ind-1}_{id_old}_{id_user}"),
                InlineKeyboardButton(
                    f"{ind + 1} / {value_length}",
                    callback_data=value_name_callback),
                InlineKeyboardButton(
                    ButtonsInput.button_next,
                    callback_data=\
                        f"{callback_next}_{ind+1}_{id_old}_{id_user}")])
    return InlineKeyboardMarkup(value_list_input[index])

def develop_output_tasks_change_type(type_list:list, type_id:int, user_id:int, task_id:int, index:int=0, type_bool:bool=False) -> object:
    """
    Function which is dedicated to return values
    Input:  type_list = lists of the selected types
            type_id = selected id of the type
            user_id = selected id of the user
            task_id = selected id of the task
            index = index which is need to return
    Output: created the values of the changeable type
    """
    if type_bool:
        callback_change = Callbacks.callback_task_new_type
        callback_next = Callbacks.callback_task_new_type_next
        number_max = 9
        number_row = 3
    else:
        callback_change = Callbacks.callback_task_new_subtype
        callback_next = Callbacks.callback_task_new_subtype_next
        number_max = 8
        number_row = 2
    value_list_input = []
    type_list = produce_list_chunks(type_list, number_max)
    value_length = len(type_list)
    for type_lists in type_list:
        value_input = []
        for ind, (id_type, name_type) in enumerate(type_lists):
            if id_type != type_id:
                value_name_type = f'{name_type}|{ButtonsInput.button_empty}'
                value_name_callback = \
                    f"{callback_change}_{task_id}_{id_type}_{type_id}_{ind}_{user_id}"
            else:
                value_name_type = f'{name_type}|{ButtonsInput.button_present}'
                value_name_callback = Callbacks.callback_empty
            value_input.append(
                InlineKeyboardButton(
                    value_name_type,
                    callback_data=value_name_callback
            ))
        value_list_input.append(value_input)
    index = index % value_length
    value_list_input = [produce_list_chunks(f, number_row) for  f in value_list_input]
    if value_length > 1:
        for ind, value_list in enumerate(value_list_input):
            value_list.append([
                InlineKeyboardButton(
                    ButtonsInput.button_previous,
                    callback_data=\
                        f"{callback_next}_{task_id}_{ind-1}_{user_id}"),
                InlineKeyboardButton(
                    f"{ind + 1} / {value_length}",
                    callback_data=value_name_callback),
                InlineKeyboardButton(
                    ButtonsInput.button_next,
                    callback_data=\
                        f"{callback_next}_{task_id}_{ind-1}_{user_id}")])
    return InlineKeyboardMarkup(value_list_input[index])

def develop_output_tasks_menu(tasks_list:list, user_id:int=0, tasks_num:int=0, exp:int=0, call=Callbacks.callback_empty) -> object:
    """
    Function which is dedicated to develop menu value of the tasks which user developed
    Input:  tasks_list = lists of tasks which were previously developed
            user_number = id of the user which it uses
            tasks_number = number of the index which is required to be developed
            tasks_exp = boolean which shows where to use expired on not
    Output: menu value of the tasks menu
    """
    tasks_number = tasks_num % len(tasks_list)
    tasks_list_input = []
    for value_task in tasks_list:
        id, status, id_user_task, morning, day, evening, type_name, id_not = value_task
        
        if status == ButtonsInput.button_processing:
            callback_id = f"{Callbacks.callback_info_tasks}_{id}_1_{user_id}"
        if status == ButtonsInput.button_expired:
            callback_id = f"{Callbacks.callback_info_tasks}_{id}_2_{user_id}"
        if status == ButtonsInput.button_finished:
            callback_id = f"{Callbacks.callback_info_tasks}_{id}_3_{user_id}"

        button_id = InlineKeyboardButton(
                id_user_task,
                callback_data=callback_id)

        button_status = InlineKeyboardButton(
            status,
            callback_data=Callbacks.callback_empty) #TODO think about this
        
        button_morning = InlineKeyboardButton(
            f"{ButtonsInput.button_morning}|{ButtonsInput.button_present}" if morning \
                else f"{ButtonsInput.button_morning}|{ButtonsInput.button_empty}",
            callback_data=\
                f"{Callbacks.callback_update_tasks_alarm}_{id}_{tasks_number}_{1}_{exp}_{user_id}")
        
        button_day = InlineKeyboardButton(
            f"{ButtonsInput.button_day}|{ButtonsInput.button_present}" if day \
                else f"{ButtonsInput.button_day}|{ButtonsInput.button_empty}",
            callback_data=\
                f"{Callbacks.callback_update_tasks_alarm}_{id}_{tasks_number}_{2}_{exp}_{user_id}")
        
        button_evening = InlineKeyboardButton(
            f"{ButtonsInput.button_evening}|{ButtonsInput.button_present}" if evening \
                else f"{ButtonsInput.button_evening}|{ButtonsInput.button_empty}",
            callback_data=\
                f"{Callbacks.callback_update_tasks_alarm}_{id}_{tasks_number}_{3}_{exp}_{user_id}")

        if status == ButtonsInput.button_processing:
            status_change = ButtonsInput.button_return_processing
            status_change_callback = \
                f"{Callbacks.callback_task_make_done}_{id}_{tasks_number}_{exp}_{call}_{user_id}"
            button_change_frequency = InlineKeyboardButton(
                f"{ButtonsInput.button_change_tasks_frequency}|{type_name}",
                callback_data=\
                    f"{Callbacks.callback_task_change_frequency}_{id}_{id_not}_{exp}_{user_id}"
            )
            button_add_timing = InlineKeyboardButton(
                ButtonsInput.button_add_timing,
                callback_data=f"{Callbacks.callback_task_add_timing}_{id}_{exp}_{user_id}"
            )
        elif status == ButtonsInput.button_expired:
            status_change = ButtonsInput.button_return_expired
            status_change_callback = \
                f"{Callbacks.callback_task_make_unexpired}_{id}_{tasks_number}_{exp}_{call}_{user_id}"
        elif status == ButtonsInput.button_finished:
            status_change = ButtonsInput.button_return_finished
            status_change_callback = \
                f"{Callbacks.callback_task_make_repeat}_{id}_{tasks_number}_{exp}_{call}_{user_id}"
        button_status_change = InlineKeyboardButton(
            status_change,
            callback_data=status_change_callback
        )
        button_change_type = InlineKeyboardButton(
            ButtonsInput.button_change_type,
            callback_data=f"{Callbacks.callback_task_change_type}_{id}_{user_id}"
        )
        button_change_subtype = InlineKeyboardButton(
            ButtonsInput.button_change_subtype,
            callback_data=f"{Callbacks.callback_task_change_subtype}_{id}_{user_id}"
        )
        value_list = [[
                button_id,
                button_status,
                button_status_change
            ],
            [
                button_morning,
                button_day,
                button_evening
            ]]
        if status == ButtonsInput.button_processing:
            value_list.insert(2,
            [
                button_change_subtype, 
                button_change_type,
                button_add_timing
            ])
            value_list.insert(3,
            [
                button_change_frequency
            ])
        else:
            value_list.insert(2,
            [
                button_change_subtype, 
                button_change_type
            ])
        if len(tasks_list) > 1:

            value_list.append([
                InlineKeyboardButton(
                    ButtonsInput.button_previous,
                    callback_data=\
                        f"{Callbacks.callback_show_next_task}_{tasks_number - 1}_{exp}_{user_id}_{call}"
                ),
                InlineKeyboardButton(
                    f"{tasks_number + 1}/{len(tasks_list)}",
                    callback_data=Callbacks.callback_empty
                ),
                InlineKeyboardButton(
                    ButtonsInput.button_next,
                    callback_data=\
                        f"{Callbacks.callback_show_next_task}_{tasks_number + 1}_{exp}_{user_id}_{call}"
                )
            ])
        tasks_list_input.append(value_list)

    return InlineKeyboardMarkup(tasks_list_input[tasks_number]) if tasks_list_input else None

def develop_output_tasks(id_user, tasks_proc, tasks_exp, tasks_fin, id_show=0, exp=0, call=Callbacks.callback_empty) -> object:
    """
    Function which is dedicated to develop the output of the tasks
    Input:  id_user = id of the selected user
            tasks_proc = list of tasks which are processing
            tasks_exp = list of tasks which are expired
            tasks_fin = list of tasks which are finished
            id_show = id of the task which is to show
            exp = int to show for the next will it be the expired calculations
    Output: developed values of the output of the tasks
    """
    tasks_proc = redevelop_values_results_task_query(tasks_proc, 1)
    tasks_exp = redevelop_values_results_task_query(tasks_exp, 2)
    tasks_fin = redevelop_values_results_task_query(tasks_fin, 3)
    if tasks_exp:
        tasks_proc.extend(tasks_exp)
    if tasks_fin:
        tasks_proc.extend(tasks_fin)
    if tasks_proc:
        return develop_output_tasks_menu(tasks_proc, id_user, id_show, exp, call)
    return None

def develop_output_tasks_type_subtype(id_count, id_name, id_callback, call, chunk=chunk_default, chunk_sub=9, index=0) -> object:
    f"""
    Function which is dedicated to develop values of the
    Input:  id_count = id and count of it selected
            id_name = id and name values of it
            id_callback = id of the selected callback within the 
            call = callback of the moving next/previously
            chunk = chunk of the previously calculated values of it; default ({chunk_default})
            chunk_sub = chunk which is about the division of values maximum inside
            index = index of the previously developed values
    Output: keyboard to develop values of it 
    """
    id_count = produce_list_chunks(id_count, chunk_sub)
    id_name = produce_list_chunks(id_name, chunk_sub)
    length_chunks = len(id_count)
    index = index % length_chunks
    id_count = id_count[index]
    id_name = id_name[index]
    value_list = []
    for (value_i, value_count), (value_j, value_name) in zip(id_count, id_name):
        if value_i == value_j and value_count > 0:
            value_list.append([
                f"{ButtonsInput.button_present}|{value_name}({value_count})", 
                f"{id_callback}_{value_i}"])
        elif value_i == value_j and value_count == 0:
            value_list.append([
                f"{ButtonsInput.button_empty}|{value_name}", 
                Callbacks.callback_empty])
    value_list = produce_list_chunks(value_list, chunk)
    value_list = [
        [
            InlineKeyboardButton(
                name, 
                callback_data=callback) 
            for name, callback in sub_list] 
        for sub_list in value_list]
    markup_selected = InlineKeyboardMarkup(value_list)
    markup_selected.row_width = 3
    markup_selected.add(
        InlineKeyboardButton(
            GroupingTasksMenu.default_select_all, 
            callback_data=f"{Callbacks.callback_select_all}_{id_callback}"))
    if id_callback != Callbacks.callback_task_selection and length_chunks > 1:
        markup_selected.add(
            InlineKeyboardButton(
                ButtonsInput.button_previous, 
                callback_data=f"{call}_{index - 1}"),
            InlineKeyboardButton(
                f'{index + 1}/{length_chunks}', 
                callback_data=Callbacks.callback_empty),
            InlineKeyboardButton(
                ButtonsInput.button_next, 
                callback_data=f"{call}_{index + 1}")
            )
    return markup_selected

def produce_list_chunks(value_list:list, chunk:int) -> list:
    """
    Function which is dedicated to make chunk lists
    Input:  value_list = list values which is used for chunks
            chunk = number which is required to make sublists
    Output: list of selected chunks of it
    """
    def chunks(value_list:list, value_len:int):
        """
        Function for chunking values of the
        Input:  value_list = original list
                value_len = length of the sublists
        Output: len on which to chunk values
        """
        for i in range(0, len(value_list), value_len):
            yield value_list[i:i + value_len]
    return list(chunks(value_list, chunk))

def check_user_chat(id_message:int) -> bool:
    """
    Function which is dedicated to check values of the 
    Input:  id_message = if of the user which is used
    Output: 
    """
    return id_message > 0